/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.max.oti.system.util;

import java.util.Iterator;
import java.util.Map;
import javax.el.ELContext;
import javax.el.ExpressionFactory;
import javax.el.MethodExpression;
import javax.el.ValueExpression;
import javax.faces.application.Application;
import javax.faces.application.FacesMessage;
import javax.faces.application.NavigationHandler;
import javax.faces.component.UIComponent;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.faces.context.Flash;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;

/**
 *
 * @author seba
 */
public class JSFUtils {

    /**
     * Metodo que retorna el facesContext
     *
     * @return el Objeto FacesContext
     */
    public static FacesContext getFacesContext() {
        return FacesContext.getCurrentInstance();
    }

    /**
     * Metodo que retorna el FlashScope
     *
     * @return
     */
    public static Flash getFlashScope() {
        return (FacesContext.getCurrentInstance().getExternalContext().getFlash());
    }

    /**
     * Metodo que para tomar una referencia a un JSF Binding y devolver (id
     * crear) un objeto resultante
     *
     * Method for taking a reference to a JSF binding expression and returning
     * the matching object (or creating it).
     *
     * @param el , la expresion EL
     * @return Object
     */
    public static void setValueToEL(String el, Object val) {
        FacesContext facesContext = FacesContext.getCurrentInstance();
        ELContext elContext = facesContext.getELContext();
        ExpressionFactory expressionFactory = facesContext.getApplication().getExpressionFactory();
        ValueExpression exp = expressionFactory.createValueExpression(elContext, el, Object.class);
        exp.setValue(elContext, val);
    }

    /**
     * Metodo que evalua una EL expression y devuelve el un objeto resultado de
     * la evaluacion
     *
     * @param el El expression a evaluar
     * @return Objeto resultante de la evalucaion
     */
    public static Object evaluateEL(String el) {
        FacesContext facesContext = FacesContext.getCurrentInstance();
        ELContext elContext = facesContext.getELContext();
        ExpressionFactory expressionFactory = facesContext.getApplication().getExpressionFactory();
        ValueExpression exp =  expressionFactory.createValueExpression(elContext, el, Object.class);
        return exp.getValue(elContext);
    }
    
    /**
     * Metodo que ejecuta una metodo dado por una EL
     *
     * @param expr EL expression que contiene el metodo a ejecutar
     * @param returnType tipo que se espera que retorne
     * @param argTypes de que tipo son los argumentos a pasar en el metodo
     * @param args argumentos a pasar en el metodo
     * @return
     */
    public static Object invokeMethodExpression(String expr, Class returnType,
            Class[] argTypes,
            Object[] args) {
        FacesContext fc = FacesContext.getCurrentInstance();
        ELContext elctx = fc.getELContext();
        ExpressionFactory elFactory =
                fc.getApplication().getExpressionFactory();
        MethodExpression methodExpr =
                elFactory.createMethodExpression(elctx, expr, returnType,
                argTypes);
        return methodExpr.invoke(elctx, args);
    }

    /**
     * Invoke an expression
     *
     * @param expr
     * @param returnType
     * @param argType
     * @param argument
     * @return
     */
    public static Object invokeMethodExpression(String expr, Class returnType,
            Class argType, Object argument) {
        return invokeMethodExpression(expr, returnType, new Class[]{argType},
                new Object[]{argument});
    }

    /**
     * Metodo que devuelve el servletContext obtenido del facesContext.
     *
     * @return
     */
    public static ServletContext getServletContext() {
        FacesContext facesContext = FacesContext.getCurrentInstance();
        ExternalContext externalContext = facesContext.getExternalContext();
        ServletContext servletContext = (ServletContext) externalContext.getContext();
        return servletContext;
    }

    /**
     * Locate an UIComponent in view root with its component id. Use a recursive
     * way to achieve this.
     *
     * @param id UIComponent id
     * @return UIComponent object
     */
    public static UIComponent findComponentInRoot(String id) {
        UIComponent component = null;
        FacesContext facesContext = FacesContext.getCurrentInstance();
        if (facesContext != null) {
            UIComponent root = facesContext.getViewRoot();
            component = findComponent(root, id);
        }
        return component;
    }

    /**
     * Locate an UIComponent from its root component. Taken from
     * http://www.jroller.com/page/mert?entry=how_to_find_a_uicomponent
     *
     * @param base root Component (parent)
     * @param id UIComponent id
     * @return UIComponent object
     */
    public static UIComponent findComponent(UIComponent base, String id) {
        if (id.equals(base.getId())) {
            return base;
        }

        UIComponent children = null;
        UIComponent result = null;
        Iterator childrens = base.getFacetsAndChildren();
        while (childrens.hasNext() && (result == null)) {
            children = (UIComponent) childrens.next();
            if (id.equals(children.getId())) {
                result = children;
                break;
            }
            result = findComponent(children, id);
            if (result != null) {
                break;
            }
        }
        return result;
    }

    /**
     * Metodo para agregar un mensaje de Error a un componente
     *
     * @param UIComponentClientID , El id HTML del componente, se puede obtener
     * con el metodo del componente getClientId()
     * @param attrName , Para agregar un mensaje al encabezado
     * @param msg , Para agregar el mensaje al cuerpo
     */
    public static void addFacesErrorMessage(String UIComponentClientID,
            String attrName, String msg) {
        FacesContext ctx = getFacesContext();
        FacesMessage fm = new FacesMessage(FacesMessage.SEVERITY_ERROR, attrName, msg);
        ctx.addMessage(UIComponentClientID, fm);
    }

    /**
     * Metodo para agregar un mensaje de Error Fatal a un componente
     *
     * @param UIComponentClientID , El id HTML del componente, se puede obtener
     * con el metodo del componente getClientId()
     * @param attrName , Para agregar un mensaje al encabezado
     * @param msg , Para agregar el mensaje al cuerpo
     */
    public static void addFacesFatalMessage(String UIComponentClientID,
            String attrName, String msg) {
        FacesContext ctx = getFacesContext();
        FacesMessage fm = new FacesMessage(FacesMessage.SEVERITY_FATAL, attrName, msg);
        ctx.addMessage(UIComponentClientID, fm);
    }

    /**
     * Metodo para agregar un mensaje de Informacion a un componente
     *
     * @param UIComponentClientID , El id HTML del componente, se puede obtener
     * con el metodo del componente getClientId()
     * @param attrName , Para agregar un mensaje al encabezado
     * @param msg , Para agregar el mensaje al cuerpo
     */
    public static void addFacesInfoMessage(String UIComponentClientID,
            String attrName, String msg) {
        FacesContext ctx = getFacesContext();
        FacesMessage fm = new FacesMessage(FacesMessage.SEVERITY_INFO, attrName, msg);
        ctx.addMessage(UIComponentClientID, fm);
    }

    /**
     * Metodo para agregar un mensaje de Advertencia a un componente
     *
     * @param UIComponentClientID , El id HTML del componente, se puede obtener
     * con el metodo del componente getClientId()
     * @param attrName , Para agregar un mensaje al encabezado
     * @param msg , Para agregar el mensaje al cuerpo
     */
    public static void addFacesWarnMessage(String UIComponentClientID,
            String attrName, String msg) {
        FacesContext ctx = getFacesContext();
        FacesMessage fm = new FacesMessage(FacesMessage.SEVERITY_WARN, attrName, msg);
        ctx.addMessage(UIComponentClientID, fm);
    }

    /**
     * Metodo que obtiene el valor de un atributo f:param definido para un
     * componente
     *
     * @param uIComponent
     * @param atributo nombre del f:param
     * @return
     */
    public static String getAttributeValue(UIComponent uIComponent, String atributo) {
        Map<String, Object> atributos = uIComponent.getAttributes();
        return atributos.get(atributo).toString();
    }

    /**
     * Metodo que fuerza a realizar una navegacion especificando un caso de
     * navegacion
     *
     * @param navigationCase
     */
    public static void invokeNavigation(String navigationCase) {
        FacesContext fctx = getFacesContext();
        Application application = fctx.getApplication();
        NavigationHandler navHandler = application.getNavigationHandler();
        navHandler.handleNavigation(fctx, null, navigationCase);
    }
    
    /**
     * Metodo que obtiene la request a partir del contexto
     * @return  HttpServletRequest
     */
    public static HttpServletRequest getRequest() {
        FacesContext facesContext = JSFUtils.getFacesContext();
        ExternalContext externalContext = facesContext.getExternalContext();
        Object request = externalContext.getRequest();
        return request instanceof HttpServletRequest ? (HttpServletRequest) request : null;
    }
}
